﻿using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.UI;
using System.Web.Security;

using MvcCms.Data.Entities;
using MvcCms.Service.Code.Wiki;
using WikiPlex;
using WikiPlex.Formatting;
using MvcCms.Data;
using MvcCmsWiki.Service;
using MvcCmsWiki.Data;
using MvcCms.Service;
using MvcCms.Service.Cache;
using MvcCmsWikiPlex.Models.ViewData;
using MvcCms.Service.Code;
using MvcCms.Service.Filters;

namespace MvcCmsWikiPlex.Controllers
{
    [HandleError]
    [RedirectToNonSslIfNotAuthenticated(Redirect = true)]
    public class WikiPlexController : MvcCms.Service.Code.BaseClasses.CMSControllerBase
    {
        private readonly IWikiService _service;
        private readonly IWikiEngine _wikiEngine;
        private readonly ICacheService _cacheService;
        private readonly IAccountService _accountService;
      
        public WikiPlexController(IWikiEngine wikiEngine, IWikiService service, ICacheService cacheService, IAccountService accountService, ICmsService cmsService, IZoneService zoneService)
            : base(cmsService, zoneService, accountService)
        {
            _service = service;
            _cacheService = cacheService;
            _wikiEngine = wikiEngine;
            _accountService = accountService;
        }

        [Authorize(Roles = "Admin")]
        public ActionResult ManageWiki()
        {
            ViewData["message"] = "";
            var viewData = new WikiModel();

            var settings = _service.GetSettings() ?? new WikiSetting();
            viewData._WikiSetting = settings;

            viewData._Portal = _cacheService.GetCurrentPortal();

            return View("ManageWiki", viewData);
        }

        private bool IsPermitted(WikiTitle wikiTitleToCheck)
        {
            if (!string.IsNullOrEmpty(wikiTitleToCheck.RestrictedToGroups))
            {
                var roles = wikiTitleToCheck.RestrictedToGroups.Split(',');
                var user = _accountService.GetUser();
                if (user == null) { return false; }
                foreach (var role in roles)
                {
                    if (Roles.IsUserInRole(user.UserName, role))
                    {
                        return true;
                    }
                }
                return false;
            }
            return true;
        }

        [CleanUrls]
        public ActionResult ViewWiki(string slug)
        {
            var viewData = new WikiModel();
            viewData._WikiContent = _service.Get(slug);
            
            if (viewData._WikiContent != null)
            {
                if (!IsPermitted(viewData._WikiContent.WikiTitle)) { return RedirectToAction("MembersOnly"); }
                ViewData["HistoryCount"] = viewData._WikiContent.WikiTitle.MaxVersion;
            }
            else
            {
                ViewData["HistoryCount"] = 0;
                return RedirectToAction("EditWiki", new { slug });
            }

            viewData._Portal = _cacheService.GetCurrentPortal();
            viewData._WikiContent.RenderedSource = _wikiEngine.Render(viewData._WikiContent.Source, GetFormatter());

            viewData._ShowEditLink = true;
            var settings = _service.GetSettings();
            if (settings != null)
            {
                if (!settings.AllowAnonymousEdit && !Request.IsAuthenticated)
                {
                    viewData._ShowEditLink = false;
                }
                else if (!settings.AllowAnonymousEdit && Request.IsAuthenticated)
                {
                    if (!Roles.IsUserInRole(settings.RoleForEdit))
                    {
                        viewData._ShowEditLink = false;
                    }
                }
            }
            else
            {
                viewData._ShowEditLink = false;
            }
            return View("View", viewData);
        }

        public ActionResult ViewWikiVersion(string slug, int version)
        {
            var viewData = new WikiModel();

            viewData._WikiContent = _service.GetByVersion(slug, version);
            if (!IsPermitted(viewData._WikiContent.WikiTitle)) { return RedirectToAction("MembersOnly"); }

            ViewData["HistoryCount"] = viewData._WikiContent.WikiTitle.MaxVersion;

            if (viewData._WikiContent == null)
                return RedirectToAction("ViewWiki", new { slug });

            viewData._Portal = _cacheService.GetCurrentPortal();
            viewData._WikiContent.RenderedSource = _wikiEngine.Render(viewData._WikiContent.Source, GetFormatter());

            viewData._ShowEditLink = true;
            var settings = _service.GetSettings();
            if (settings != null)
            {
                if (!settings.AllowAnonymousEdit && !Request.IsAuthenticated)
                {
                    viewData._ShowEditLink = false;
                }
                else if (!settings.AllowAnonymousEdit && Request.IsAuthenticated)
                {
                    if (!Roles.IsUserInRole(settings.RoleForEdit))
                    {
                        viewData._ShowEditLink = false;
                    }
                }
            }
            else
            {
                viewData._ShowEditLink = false;
            }
            return View("View", viewData);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "Admin")]
        public ActionResult EditWikiSettings(WikiSetting wikiSettingToEdit)
        {
            int settingId = wikiSettingToEdit.WikiSettingID;
            var settings = _service.SaveSettings(wikiSettingToEdit);
            var viewData = new WikiModel();
            viewData._Portal = _cacheService.GetCurrentPortal();

            if (settings != null)
            {
                ViewData["message"] = "Settings Change Successful";
            }
            else
            {
                ViewData["message"] = "An error occured";
                if (wikiSettingToEdit.WikiSettingID == 0)
                {
                    settings = new WikiSetting();
                }
                else
                {
                    settings = _service.GetSettings();
                }
                viewData._WikiSetting = settings;
                return View("ManageWiki", viewData);
            }
            if (settingId == 0)
            {
                return RedirectToAction("ViewWiki");
            }
            viewData._WikiSetting = settings;
            return View("ManageWiki", viewData);
        }

        private MacroFormatter GetFormatter()
        {
            var siteRenderers = new IRenderer[] 
            { 
                new TitleLinkRenderer(Url), 
                new TextColorRenderer() ,
                new TextSizeRenderer(),
                new AnyStyleRenderer(),
            };
            IEnumerable<IRenderer> allRenderers = Renderers.All.Union(siteRenderers);
            return new MacroFormatter(allRenderers);
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult EditWiki(string slug)
        {
            var content = _service.Get(slug) ?? new DTOWikiContent
                                                    {
                                                        WikiTitle = new WikiTitle { Slug = slug }
                                                    };

            var settings = _service.GetSettings();
            if (settings != null)
            {
                if (!settings.AllowAnonymousCreate)
                {
                    if (!Request.IsAuthenticated)
                    {
                        return RedirectToAction("ViewWiki", new { slug = "" });
                    }
                    if (!Roles.IsUserInRole(settings.RoleForCreate))
                    {
                        return RedirectToAction("ViewWiki", new { slug = "" });
                    }
                }
            }
            else
            {
                var currentPortal = _cacheService.GetCurrentPortal();
                var currentUser = _accountService.GetUser();
                //lets make some default settings for this wiki
                var settingsToCreate = new WikiSetting
                {
                    AllowAnonymousCreate = false,
                    AllowAnonymousEdit = false,
                    Portal = currentPortal,
                    RoleForCreate = "user", 
                    RoleForEdit = "user"                    
                };
                _service.SaveSettings(settingsToCreate);
                //now lets make their homepage after we make sure they are logged in
                if (currentUser == null) { return Redirect("http://" + currentPortal.URLAuthority); }
                _service.Save(slug, currentPortal.DisplayName, "Welcome to " + currentPortal.DisplayName + " wiki.", _accountService.GetUser(), "");
                return RedirectToAction("ViewWiki", new { slug = "home" });
            }
            return View("Edit", content);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [ValidateInput(false)]
        public ActionResult EditWiki(string slug, string name, string source, string restrictedToGroups)
        {
            var user = _accountService.GetUser();
            if (user == null)
            {
                user = _accountService.GetUser("anonymous");
            }
            var settings = _service.GetSettings();
            if (settings != null)
            {
                if (!settings.AllowAnonymousCreate)
                {
                    if (!Request.IsAuthenticated)
                    {
                        return RedirectToAction("ViewWiki", new { slug = "" });
                    }
                    if (!Roles.IsUserInRole(settings.RoleForCreate))
                    {
                        return RedirectToAction("ViewWiki", new { slug = "" });
                    }
                }
                _service.Save(slug, name, source, user, restrictedToGroups);   
            }
            else
            {
                _service.Save(slug, name, source, user, restrictedToGroups);                
            }
            return RedirectToAction("ViewWiki", new { slug });
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [OutputCache(Location = OutputCacheLocation.None)]
        public string GetWikiSource(string slug, int version)
        {
            var content = _service.GetByVersion(slug, version);

            return content.Source;
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [OutputCache(Location = OutputCacheLocation.None)]
        [ValidateInput(false)]
        public string GetWikiPreview(string slug, string source)
        {
            return _wikiEngine.Render(source, GetFormatter());
        }

        public ActionResult MembersOnly()
        {
            return View();
        }
    }
}